﻿#include "KLineBarLayer.h"
#include <QPainter>

#include "KLineCanvasContext.h"
#include "KLineViewContext.h"
#include "KColorStyle.h"
#include "KBarWidthStyle.h"

class KLineBarLayer::KLineBarLayerPrivate :public QObject
{
public:
	QVector<QVariant> open, close, high, low;
	//KLineViewContext*view_context;
	//int globalcolor_index;
	//QColor line_color; 
public:
	KLineBarLayerPrivate(QObject*parent):QObject(parent)
	{
		//view_context = nullptr;
		//globalcolor_index = -1;

		//open.append(10.0);
		//close.append(11);
		//high.append(12);
		//low.append(9.5);

		//open.append(8);
		//close.append(7);
		//high.append(10);
		//low.append(6);
	}
	void getValue(int idx, double*_open, double*_close, double*_high, double*_low)
	{
		*_open = open[idx].toDouble();
		*_close = close[idx].toDouble();
		*_high = high[idx].toDouble();
		*_low = low[idx].toDouble();
	}
};

KLineBarLayer::KLineBarLayer(QObject *parent)
	: KLineLayer(parent),private_ptr(new KLineBarLayerPrivate(this))
{
	setType(KLayer::LAYER_TYPE_KLINE);
}

KLineBarLayer::~KLineBarLayer()
{
}

//void KLineBarLayer::setViewContext(KLineViewContext*_)
//{
//	private_ptr->view_context = _;
//}
//
//void KLineLayer::setData(QVector<QVariant>*open, QVector<QVariant>*close, QVector<QVariant>*high, QVector<QVariant>*low)
//{
//	private_ptr->open = *open;
//	private_ptr->close = *close;
//	private_ptr->high = *high;
//	private_ptr->low = *low;
//}
//

//void KLineBarLayer::setColor(int global_idx)
//{
//	private_ptr->globalcolor_index = global_idx;
//}
//void KLineBarLayer::setColor(const QColor&clr)
//{
//	private_ptr->globalcolor_index = -1;
//	private_ptr->line_color = clr;
//}
//QColor KLineBarLayer::color()
//{
//	if (private_ptr->globalcolor_index < 0)
//		return private_ptr->line_color;
//
//	return private_ptr->view_context->canvas_context->color_style->color(private_ptr->globalcolor_index);
//}
static void drawBar(QPainter*p, QRectF rc, KBarWidthStyleItem*item, int pos_open, int pos_close, int pos_high, int pos_low, const QColor& clr)
{
	int line_x = rc.left() + item->center();
	rc.setLeft(rc.left() + item->left_space);
	//rc.setWidth(item->inner_width);
	rc.setRight(rc.right() - item->right_space);
	QLineF line_up, line_down;
	if (pos_open > pos_close) { // 空心
		rc.setTop(pos_close);
		rc.setBottom(pos_open);
		p->setBrush(Qt::BrushStyle::NoBrush);
		line_up.setLine(line_x, pos_high, line_x, pos_close);
		line_down.setLine(line_x, pos_open ,line_x, pos_low);
	}
	else {
		rc.setTop(pos_open);
		rc.setBottom(pos_close);
		p->setBrush(clr);
		line_up.setLine(line_x, pos_high, line_x, pos_open);
		line_down.setLine(line_x, pos_close ,line_x, pos_low);
	}

	p->setPen(clr);
	p->drawLine(line_up);
	p->drawLine(line_down);
	p->drawRect(rc);
}
static QColor getBarColor(KColorStyle*style, int pos_open, int pos_close)
{
	// 位置越高，值越大
	if (pos_open < pos_close)
		return style->color(KColorStyle::KCOLOR_KLINE_GREEN);
	if (pos_open > pos_close)
		return style->color(KColorStyle::KCOLOR_KLINE_RED);

	return style->color(KColorStyle::KCOLOR_KLINE_WHITE);
}
void KLineBarLayer::draw(QPainter*p)
{
	if (!visible())
		return;

	int count = dataLength();
	if (!count)
		return;

	KLineViewContext * ctx = viewContext();
	KLineCanvasContext*canvas_ctx = ctx->canvas_context;
	if (0 == canvas_ctx->canvas_colcount)
		return;


	int n = count - canvas_ctx->item_startidx;
	if (n <= 0)
		return;

	int endidx = count - 1;
	if (canvas_ctx->item_startidx + canvas_ctx->canvas_colcount - 1 <= endidx)
		endidx = canvas_ctx->item_startidx + canvas_ctx->canvas_colcount - 1;

	//QPoint pt;
	//QPolygon polygon;

	double open = 0, close, high, low;
	int pos_open, pos_close, pos_high, pos_low;

	QRectF rc = canvas_ctx->rect_firstcol;// .intersected(private_ptr->view_context->rt_view);
	KBarWidthStyleItem*bar_item = KBarWidthStyle::item(canvas_ctx->barwidthstyle_idx);// ->center();

	p->save();
	//p->setClipRect(private_ptr->view_context->rt_view);

	for (int i = canvas_ctx->item_startidx; i <= endidx; i++) {
		if (i != canvas_ctx->item_startidx)
			rc.translate(canvas_ctx->canvas_colwidth, 0);

		private_ptr->getValue(i, &open, &close, &high, &low);
		pos_open = ctx->posYAtValue(open);
		pos_close = ctx->posYAtValue(close);
		pos_high = ctx->posYAtValue(high);
		pos_low = ctx->posYAtValue(low);

		drawBar(p, rc, bar_item, pos_open, pos_close, pos_high, pos_low, getBarColor(canvas_ctx->color_style, pos_open, pos_close));

		//pt.setX(rc.left() + baritem_center);
		//pt.setY(private_ptr->view_context->posYAtValue(private_ptr->data[i].toDouble()));
		//polygon.append(pt);
	}

	//QPainterPath	pp;
	//pp.addPolygon(polygon);

	//p->setPen(color());
	//p->drawPath(pp);

	p->restore();
}

bool KLineBarLayer::contain(const QPointF&pt)
{
	return false;
}
int KLineBarLayer::dataLength()
{
	int r = 0;
	int n1 = private_ptr->open.count();
	int n2 = private_ptr->close.count();
	int n3 = private_ptr->high.count();
	int n4 = private_ptr->low.count();
	if (n1 > r) r = n1;
	if (n2 > r) r = n2;
	if (n3 > r) r = n3;
	if (n4 > r) r = n4;

	return r;
}
void KLineBarLayer::setData(int type, QVector<QVariant>*_)
{
	switch (type) {
	case OPEN: 
		if (_)
			private_ptr->open = *_;
		else
			private_ptr->open.clear();
		break;
	case CLOSE:
		if (_)
			private_ptr->close = *_;
		else
			private_ptr->close.clear();
		break;
	case HIGH: 
		if (_)
			private_ptr->high = *_; 
		else
			private_ptr->high.clear();
		break;
	case LOW: 
		if (_)
			private_ptr->low = *_; 
		else
			private_ptr->low.clear();
		break;
	}
}
QVector<QVariant>* KLineBarLayer::data(int type)
{
	switch (type) {
	case OPEN:		return &private_ptr->open; 
	case CLOSE:		return &private_ptr->close; 
	case HIGH:		return &private_ptr->high; 
	case LOW:		return &private_ptr->low; 
	}
	return KLineLayer::data(type);
}
bool KLineBarLayer::getMaxMinValue(int start_idx, int count, double*max_v, double*min_v)
{
	int len = dataLength();
	if (start_idx >= len)
		return false;

	int n = len - start_idx;
	if (start_idx < 0 || !n || !count) {
		return false;
	}
	if (n < count)
		count = n;

	bool ok = false;
	//double axv, inv, t;

	int end_idx = start_idx + count - 1;


	double axv = -DBL_MAX, inv = DBL_MAX, t;
	for (int i = start_idx; i <= end_idx; i++) {
	//for (auto a : private_ptr->high) {
		t = private_ptr->high[i].toDouble();
		if (t > axv)
			axv = t;
	}

	inv = axv;
	for (int i = start_idx; i <= end_idx; i++) {
		t = private_ptr->low[i].toDouble();
		if (t < inv)
			inv = t;
	}

	if (axv == -DBL_MAX || inv == DBL_MAX)
		return false;

	*max_v = (axv);
	*min_v = (inv);
	return true;
}

